package com.qing.springcloud.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO;
import com.qing.springcloud.common.*;
import com.qing.springcloud.dao.GroupMemberDao;
import com.qing.springcloud.dao.GroupMessageReadDao;
import com.qing.springcloud.dao.MessageDao;
import com.qing.springcloud.dao.UserFriendDao;
import com.qing.springcloud.dto.message.GroupMessageDTO;
import com.qing.springcloud.dto.message.MessageDTO;
import com.qing.springcloud.dto.message.MessageReadDTO;
import com.qing.springcloud.dto.message.PrivateMessageDTO;
import com.qing.springcloud.entity.GroupMessageRead;
import com.qing.springcloud.entity.Message;
import com.qing.springcloud.exception.BusinessException;
import com.qing.springcloud.model.ChatMessage;
import com.qing.springcloud.utils.EnumUtils;
import com.qing.springcloud.utils.PageResult;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import com.qing.springcloud.service.MessageService;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * 消息存储表 
服务接口实现
 *
 * @author zhipeng.cao
 * @since 2025-07-09 20:09:50
 * @description 由 Mybatisplus Code Generator 创建
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class MessageServiceImpl implements MessageService {

    private final MessageDao messageDao;
    private final GroupMessageReadDao groupMessageReadDao;
    private final UserFriendDao userFriendDao;
    private final GroupMemberDao groupMemberDao;
    private final RabbitTemplate rabbitTemplate;

    @Override
    public void sendPrivateMessage(ChatMessage chatMessage) {
        // 验证好友关系
        if (!userFriendDao.existsByUserIdAndFriendId(chatMessage.getSenderId(), chatMessage.getReceiverId())) {
            throw new BusinessException("对方不是您的好友");
        }

        // 创建消息实体
        Message message = new Message();
        message.setMsgId(IdUtil.getSnowflakeNextIdStr());
        message.setMsgType(chatMessage.getMsgType());
        message.setContent(chatMessage.getContent());
        message.setSenderId(chatMessage.getSenderId());
        message.setReceiverId(chatMessage.getReceiverId());
        message.setChatType(MessageChatTypeEnum.PRIVATE.getCode());
        message.setStatus(MessageStatusEnum.SENT.getCode());
        message.setSendTime(DateUtil.date());
        message.setExtra(chatMessage.getExtra());
        messageDao.save(message);

        // 创建RabbitMQ消息

        chatMessage.setMsgId(message.getMsgId());
        chatMessage.setChatType(MessageChatTypeEnum.PRIVATE.getCode());
        chatMessage.setTimestamp(DateUtil.current());

        // 通过RabbitMQ发送
        rabbitTemplate.convertAndSend("direct_exchange", chatMessage.getReceiverId().toString(), chatMessage);
    }

    @Override
    public void sendGroupMessage(ChatMessage chatMessage) {
        // 验证群成员身份
        if (!groupMemberDao.existsActiveMember(chatMessage.getReceiverId(), chatMessage.getSenderId())) {
            throw new BusinessException("你不在群聊中");
        }

        // 创建消息实体
        Message message = new Message();
        message.setMsgId(IdUtil.getSnowflakeNextIdStr());
        message.setMsgType(chatMessage.getMsgType());
        message.setContent(chatMessage.getContent());
        message.setSenderId(chatMessage.getSenderId());
        message.setReceiverId(chatMessage.getReceiverId());
        message.setChatType(MessageChatTypeEnum.GROUP.getCode());
        message.setStatus(MessageStatusEnum.SENT.getCode());
        message.setSendTime(DateUtil.date());
        message.setExtra(chatMessage.getExtra());
        messageDao.save(message);

        // 为群聊初始化消息阅读状态
        initGroupMessageReadStatus(message.getMsgId(), chatMessage.getReceiverId());

        // 创建RabbitMQ消息
        chatMessage.setMsgId(message.getMsgId());
        chatMessage.setChatType(MessageChatTypeEnum.GROUP.getCode());
        chatMessage.setTimestamp(DateUtil.current());

        // 通过Fanout Exchange广播
        rabbitTemplate.convertAndSend("group_exchange_" + chatMessage.getReceiverId(), "", chatMessage);
    }

    private void initGroupMessageReadStatus(String msgId, Long groupId) {
        List<Long> memberIds = groupMemberDao.findActiveMemberIds(groupId);
        for (Long memberId : memberIds) {
            GroupMessageRead read = new GroupMessageRead();
            read.setMsgId(msgId);
            read.setGroupId(groupId);
            read.setUserId(memberId);
            read.setReadStatus(GroupMessageReadStatusEnum.UNREAD.getCode());
            groupMessageReadDao.save(read);
        }
    }

    @Override
    public void markMessageRead(ChatMessage chatMessage) {
        Long receiverId = chatMessage.getReceiverId();
        List<String> msgIds = chatMessage.getMsgIds();
        if (EnumUtils.equals(chatMessage.getChatType(),MessageChatTypeEnum.PRIVATE)) {
            // 私聊消息更新状态
            messageDao.updateStatusToDelivered(msgIds, receiverId);
            messageDao.updateStatusToRead(msgIds, receiverId, DateUtil.date());
        } else {
            // 群聊消息更新阅读状态
            for (String msgId : msgIds) {
                GroupMessageRead read = groupMessageReadDao.findByMsgIdAndUserId(msgId, receiverId)
                        .orElseThrow(() -> new BusinessException("消息不存在"));

                read.setReadStatus(GroupMessageReadStatusEnum.READ.getCode());
                read.setReadTime(DateUtil.date());
                groupMessageReadDao.save(read);
            }

            // 更新主消息状态（当所有成员都已读）
            checkAndUpdateGroupMessageStatus(msgIds.get(0));
        }
    }


    private void checkAndUpdateGroupMessageStatus(String msgId) {
        GroupMessageRead read = groupMessageReadDao.findFirstByMsgId(msgId)
                .orElseThrow(() -> new BusinessException("消息不存在"));

        long totalCount = groupMessageReadDao.countByMsgId(msgId);
        long readCount = groupMessageReadDao.countByMsgIdAndReadStatusTrue(msgId);

        if (readCount == totalCount) {
            Message message = messageDao.findByMsgId(msgId)
                    .orElseThrow(() -> new BusinessException("消息不存在"));
            message.setStatus(MessageStatusEnum.READ.getCode());
            messageDao.save(message);
        }
    }

    /**
     * 获取私聊信息记录
     *
     * @param userId   用户ID
     * @param friendId 好友ID
     * @param page     页码
     * @param size     每页大小
     * @return 消息记录列表
     */
    @Override
    public PageResult<MessageDTO> getPrivateMessages(Long userId, Long friendId, long page, long size) {
        Page<Message> pageable=messageDao.findPrivateChatHistory(userId, friendId, PageDTO.of(page, size));
        return  PageResult.builder(pageable,convertToDTO(pageable));
    }

    /**
     * 获取群聊消息记录
     *
     * @param groupId 群聊ID
     * @param page    页码
     * @param size    每页大小
     * @return 消息记录列表
     */
    @Override
    public PageResult<MessageDTO> getGroupMessages(Long groupId, long page, long size) {
        Page<Message> pageable =messageDao.findByReceiverIdAndChatType(groupId, MessageChatTypeEnum.GROUP.getCode(), PageDTO.of(page, size));
        return  PageResult.builder(pageable,convertToDTO(pageable));
    }

    @Override
    public void storeOfflineMessage(ChatMessage message) {
        // 当用户离线时存储消息到数据库
        Message entity = new Message();
        entity.setMsgId(message.getMsgId());
        entity.setMsgType(message.getMsgType());
        entity.setContent(message.getContent());
        entity.setSenderId(message.getSenderId());
        entity.setReceiverId(message.getReceiverId());
        entity.setChatType(message.getChatType());
        entity.setStatus(MessageStatusEnum.OFFLINE.getCode());
        entity.setSendTime(DateUtil.date(message.getTimestamp()));
        messageDao.save(entity);

        // 群消息需要初始化阅读状态
        if (EnumUtils.equals(message.getChatType(),MessageChatTypeEnum.GROUP)) {
            initGroupMessageReadStatus(message.getMsgId(), message.getReceiverId());
        }
    }

    @Override
    public List<ChatMessage> getOfflineMessages(Long userId) {
        List<Message> offlineMsgList= messageDao.list(new QueryWrapper<Message>()
               .eq("receiver_id", userId)
               .eq("status", MessageStatusEnum.OFFLINE.getCode())
               .orderByDesc("send_time") );
        if(CollUtil.isNotEmpty(offlineMsgList)){
           return offlineMsgList.stream().map(message -> {
                ChatMessage chatMessage=new ChatMessage();
                BeanUtils.copyProperties(message,chatMessage);
                return chatMessage;
            }).toList();
        }
        return List.of();
    }

    private List<MessageDTO> convertToDTO(List<Message> messages) {
        return messages.stream().map(this::convertToDTO).collect(Collectors.toList());
    }
    private List<MessageDTO> convertToDTO(Page<Message> pageable) {
        return Optional.ofNullable(pageable.getRecords()).map(this::convertToDTO).orElse(null);
    }

    private MessageDTO convertToDTO(Message message) {
        return MessageDTO.builder()
                .msgId(message.getMsgId())
                .msgType(message.getMsgType())
                .content(message.getContent())
                .senderId(message.getSenderId())
                .receiverId(message.getReceiverId())
                .chatType(message.getChatType())
                .status(message.getStatus())
                .sendTime(message.getSendTime())
                .build();
    }
}